package com.biye.auth.controller;

import com.alibaba.fastjson.JSONObject;
import com.base.common.edu.entity.LoginFail;
import com.base.common.edu.entity.Staff;
import com.base.common.edu.entity.Student;
import com.base.common.edu.util.MailUtil;
import com.base.common.edu.util.RequestUtil;
import com.base.common.httpStatusCode.enumDefine.StatusCode;
import com.base.common.security.util.EncryptUtil;
import com.base.common.security.util.JWTUtil;
import com.biye.auth.service.UserLoginService;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.security.GeneralSecurityException;
import java.util.*;

@Controller
public class UserController {

    @Autowired
    private UserLoginService userLoginService;

    /**
     * 验证码工具
     */
    @Resource
    private DefaultKaptcha defaultKaptcha;

    @RequestMapping(value = "/defaultKaptcha", method = RequestMethod.GET)
    public void defaultKaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
        byte[] captcha = null;
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        try {
            // 将生成的验证码保存在session中
            String createText = defaultKaptcha.createText();
            System.out.println(createText);
            request.getSession().setAttribute("rightCode", createText);
            BufferedImage bi = defaultKaptcha.createImage(createText);
            ImageIO.write(bi, "jpg", out);
        } catch (Exception e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        captcha = out.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream sout = response.getOutputStream();
        sout.write(captcha);
        sout.flush();
        sout.close();
    }

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    @ResponseBody
    public JSONObject loginAndGrantToken(HttpServletRequest request,HttpServletResponse response,
                                         @RequestParam(value = "captcha", required = false, defaultValue = "") String inputCaptcha,  // 验证码儿
                                         @RequestParam(value = "username", required = false, defaultValue = "") String username,  // 用户名
                                         @RequestParam(value = "password", required = false, defaultValue = "") String password,
                                         @RequestParam(value = "userType", required = false, defaultValue = "") String userType)  // 密码
    {
        JSONObject json = new JSONObject();
        String msg = "登录失败，验证信息不正确！";
        int statusCode = StatusCode.Failure._statusCode;
        // 第一步，先验证验证码信息
        String verifyCode = (String) request.getSession().getAttribute("rightCode");
        if (inputCaptcha == null || "".equals(inputCaptcha)){
            msg = "请填写验证码信息！" ;
            json.put("msg", msg);
            json.put("statusCode", statusCode);
            return json;
        }
        if ( !inputCaptcha.equals(verifyCode) ){
            msg = "验证码信息有误！" ;
            json.put("msg", msg);
            json.put("statusCode", statusCode);
            return json;
        }
        if ("".equals(userType)){
            msg = "用户身份类型未选择！" ;
            json.put("msg", msg);
            json.put("statusCode", statusCode);
            return json;
        }
        // 第二步，判断判断用户名或密码是否为空
        if ("".equals(username) || "".equals(password)){
            msg = "请填写用户名和密码信息！" ;
            json.put("msg", msg);
            json.put("statusCode", statusCode);
            return json;
        }
        // 获取登录的操作系统信息
        String browserName = RequestUtil.getBrowserName(request) == null ? "未使用浏览器" : RequestUtil.getBrowserName(request);
        String browserVersion;
        try{
            browserVersion = RequestUtil.getBrowserVersion(request) != null ? RequestUtil.getBrowserVersion(request) : "未使用浏览器即未知版本";
        }catch (NullPointerException e){
            browserVersion = "浏览器版本未知";
        }
        String osName = RequestUtil.getOsName(request) == null ? "操作系统未知" : RequestUtil.getOsName(request);
        String ipAddress = RequestUtil.getIpAddress(request);
        String info_OS = "[OS-Name：" + osName + "][Browser-Name：" + browserName + "][Browser-Version：" + browserVersion + "]";
        // 第三步，判断当前用户之前是否有在当前ip地址下，一小时内登录失败等于或超过三次
        int loginCount = userLoginService.queryLoginFailByUserAndIp(username, ipAddress);
        if ( loginCount >= 3 ) {
            // 若符合条件，则不允许登录
            msg = "一小时内连续登录失败超过三次，限制登录，请稍后再试！" ;
            // 本次登录信息亦保存
            LoginFail lf = new LoginFail();
            lf.setLogin_ip(ipAddress);
            lf.setLogin_num(username);
            lf.setLogin_pasw(password);
            lf.setLogin_os(info_OS);
            userLoginService.saveLoginFail(lf);
            json.put("msg", msg);
            json.put("statusCode", statusCode);
            return json;
        }
        // 将前端传过来的登录密码再一次加密，则当前的密码被赋值为二次加密的密码
        password = EncryptUtil.getMD5String(password);
        // 根据用户的身份，验证登录信息，信息正确则发放token
        if( "2".equals(userType) || "3".equals(userType)){
            Staff staff = userLoginService.staffLogin(username, password);
            if (staff == null) staff = userLoginService.staffLoginUseEmail(username, password);
            if (staff != null){
                statusCode = StatusCode.Success._statusCode;
                msg = "信息验证通过，欢迎登录";
                json.put("username", staff.getName());
                json.put("userType", "tea");
                json.put("userId", staff.getStaffId());
                try {
                    String token = JWTUtil.sign_in(username, staff.getStaffId(), "tea");
                    if( token == null )
                        throw new Exception();
                    // TokenAuthenticationFilter, 我的SpringSecurity过滤器中对token-Header进行拦截并验证。Header定义为Identifier
                    response.setHeader("Identifier", token);
                }catch (Exception e){
                    msg = "系统内部业务繁忙，请稍后再试，谢谢！";
                    statusCode = StatusCode.Failure._statusCode;
                }
            }else if (staff == null){
                LoginFail lf = new LoginFail();
                lf.setLogin_ip(ipAddress);
                lf.setLogin_num(username);
                lf.setLogin_pasw(password);
                lf.setLogin_os(info_OS);
                userLoginService.saveLoginFail(lf);
            }
        }else if ( "1".equals(userType) ){
            Student student = userLoginService.stuLogin(username, password);
            if (student == null) student = userLoginService.studentLoginUseEmail(username, password);
            if(student != null) {
                statusCode = StatusCode.Success._statusCode;
                msg = "信息验证通过，欢迎登录";
                json.put("username", student.getStuName());
                json.put("userType", "stu");
                json.put("userId", student.getStuID());
                try {
                    String token = JWTUtil.sign_in(username, student.getStuID(), "stu");
                    if( token == null )
                        throw new Exception();
                    // TokenAuthenticationFilter, 我的SpringSecurity过滤器中对token-Header进行拦截并验证。Header定义为Identifier
                    response.setHeader("Identifier", token);
                }catch (Exception e){
                    msg = "系统内部业务繁忙，请稍后再试，谢谢！";
                    statusCode = StatusCode.Failure._statusCode;
                }
            }else if (student == null){
                LoginFail lf = new LoginFail();
                lf.setLogin_ip(ipAddress);
                lf.setLogin_num(username);
                lf.setLogin_pasw(password);
                lf.setLogin_os(info_OS);
                userLoginService.saveLoginFail(lf);
            }
        }
        json.put("msg", msg);
        json.put("statusCode", statusCode);
        return json;
    }

    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    @ResponseBody
    public JSONObject loginAndRevokeToken(HttpServletResponse response){
        JSONObject json = new JSONObject();
        String msg = "已退出登录！";
        int statusCode = StatusCode.Success._statusCode;
        try {
            String token = JWTUtil.sign_out("guest", "guest", "guest");
            if( token == null )
                throw new Exception();
            // TokenAuthenticationFilter, 我的SpringSecurity过滤器中对token-Header进行拦截并验证。Header定义为Identifier
            response.setHeader("Identifier", token);
        }catch (Exception e){
            msg = "系统内部业务繁忙，请稍后再试，谢谢！";
            statusCode = StatusCode.Failure._statusCode;
        }
        json.put("msg", msg);
        json.put("statusCode", statusCode);
        return json;
    }

    // 邮箱找回密码属于准废弃功能，后续只允许系统管理员手工重置密码：生成验证码存于session并向用户邮箱发送验证码
    /**
     * String user_type = (String) map.get("user_type");
     * String user_mail = (String) map.get("user_mail");
     **/
    @RequestMapping(value = "/find_p_c", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public JSONObject findbackPassword_getCode(@RequestBody Map<String, Object> map, HttpServletRequest request){
        JSONObject json = new JSONObject();
        String msg = "系统中无使用此邮箱账户";
        int statusCode = StatusCode.Failure._statusCode;
        // 生成随机六位验证码
        String code = "";
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            int r = random.nextInt(10); //每次随机出一个数字（0-9）
            code = code + r;  //把每次随机出的数字拼在一起
        }
        // 根据用户身份判断邮箱是否存在
        String user_type = (String) map.get("user_type");
        String user_mail = (String) map.get("user_mail");
        if (!map.containsKey("user_type") || "".equals(user_type)){
            msg = "参数\"用户类型\"不可为空";
            json.put("statusCode", statusCode);
            json.put("msg", msg);
            return json;
        }
        if (!map.containsKey("user_mail") || "".equals(user_mail)){
            msg = "参数\"用户邮箱\"不可为空";
            json.put("statusCode", statusCode);
            json.put("msg", msg);
            return json;
        }
        String userId = "";
        if ( "tea".equals(user_type) ){
            Staff staff = new Staff();
            staff.setEmail(user_mail);
            List<Staff> staff1 = userLoginService.queryStaff(staff);
            if ( staff1.size() > 0 || staff1.size() == 1)
                userId = staff1.get(0).getStaffId();
        }else if("stu".equals(user_type)) {
            Student student = new Student();
            student.setEmail(user_mail);
            List<Student> students = userLoginService.queryStudents(student);
            if ( students.size() > 0 || students.size() == 1)
                userId = students.get(0).getStuID();
        }
        // 如果系统中有使用该邮箱的用户，那么userId当前不为空值
        if ( !"".equals(userId) ){
            msg = "系统内部发送验证码业务繁忙，请稍后再试，谢谢！";
            // 一，尝试将验证码发送到邮箱
            // 验证码
            request.getSession().setAttribute("emailCode", code);
            // 本次验证码可用尝试次数
            request.getSession().setAttribute("tryCount",3);
            // 设置用户id
            request.getSession().setAttribute("userId",userId);
            // 设置用户类型
            request.getSession().setAttribute("user_type",user_type);
            // 邮箱联系人设置
            Map<String, List<String>> receiveMap = new HashMap<>();
            // 设置接收人
            List<String> TO = new ArrayList<>();
            TO.add(user_mail);
            // 设置抄送人
            List<String> CC = new ArrayList<>();
            // 设置密送人
            List<String> BCC = new ArrayList<>();
            // 将联系人写到map中
            receiveMap.put("TO", TO);
            receiveMap.put("CC", CC);
            receiveMap.put("BCC", BCC);
            boolean result = false;
            try {
                result = MailUtil.sendMailHTML("EDU系统-邮箱密码找回", receiveMap, "您当前账户正在进行邮箱重置密码操作，本次验证码为：" + code + ", 当前验证码您有三次尝试机会，谢谢！");
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            }
            if (result){
                statusCode = StatusCode.Success._statusCode;
                msg = "验证码儿已发送到用户绑定的邮箱中，请注意查收";
            }
        }
        json.put("statusCode", statusCode);
        json.put("msg", msg);
        return json;
    }

    // 邮箱找回密码属于准废弃功能，后续只允许系统管理员手工重置密码：用户将邮箱收到的验证码与session中的验证码比对，并修改密码
    /**
     * String tobe_verifyCode = (String) map.get("emailCode");
     * String new_password = (String) map.get("newpaswd");
     **/
    @RequestMapping(value = "/find_c_c", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public JSONObject findbackPassword_checkCode(@RequestBody Map<String, Object> map, HttpServletRequest request){
        JSONObject json = new JSONObject();
        String msg = "修改密码失败，请重新尝试";
        int statusCode = StatusCode.Failure._statusCode;
        // 首先校验验证码的正确性
        if (!map.containsKey("emailCode")){
            msg = "参数\"验证码\"不可为空";
            json.put("statusCode", statusCode);
            json.put("msg", msg);
            return json;
        }
        if (!map.containsKey("newpaswd")){
            msg = "参数\"新密码\"不可为空";
            json.put("statusCode", statusCode);
            json.put("msg", msg);
            return json;
        }
        String tobe_verifyCode = (String) map.get("emailCode");
        String new_password = (String) map.get("newpaswd");
        // 获取session中的参数，用于对照的验证码
        String rightCode = (String) request.getSession().getAttribute("emailCode");
        // 本次验证码可用尝试次数
        Integer tryCount = (Integer) request.getSession().getAttribute("tryCount");
        // 设置用户id
        String userId = (String) request.getSession().getAttribute("userId");
        if (tryCount == 0){
            msg = "您的尝试机会已用尽，请重新获取验证码";
        }
        if ( !tobe_verifyCode.equals(rightCode) ){
            tryCount -= 1;
            msg = "验证码校验不通过,您还有" + tryCount + "次尝试机会（若尝试机会用尽，请尝试重新获取验证码）";
            request.getSession().setAttribute("tryCount", tryCount);
        }else if( tobe_verifyCode.equals(rightCode) ){
            // 根据用户类型重置新密码
            String user_type = (String) request.getSession().getAttribute("user_type");
            if ( "tea".equals(user_type) ){
                Staff staff = new Staff();
                staff.setStaffId(userId);
                staff.setPasswd(EncryptUtil.getMD5String(new_password));
                int affectLine = userLoginService.updateSatff(staff);
                if ( affectLine > 0 ){
                    msg = "修改密码成功";
                    statusCode = StatusCode.Success._statusCode;
                }
            }else if("stu".equals(user_type)) {
                Student student = new Student();
                student.setStuID(userId);
                student.setPassword(EncryptUtil.getMD5String(new_password));
                int affectLine = userLoginService.updateStudent(student);
                if ( affectLine > 0  ){
                    msg = "修改密码成功";
                    statusCode = StatusCode.Success._statusCode;
                }
            }
        }
        json.put("statusCode", statusCode);
        json.put("msg", msg);
        return json;
    }

}
